#include "EpilExpressionParser.h"
#include "EpilParserUtilities.h"
#include "EpilUnaryExpressionCode.h"
#include "EpilBinaryExpressionCode.h"
#include "EpilSimpleExpressionParser.h"
#include "EpilPointerHelper.h"


EpilExpressionParser::EpilExpressionParser( EpilTokenStream & tokens )
: EpilSyntaxParserBase( tokens )
{
}


void EpilExpressionParser::Parse()
{
	this->ParseWithOperatorPrecedence( 0 );
}


void EpilExpressionParser::ParseWithOperatorPrecedence( int precedence )
{
	// subexpr -> (simpleexp | unop subexpr) { binop subexpr }

	EpilExpressionCodeBase * leftExpr = NULL;

	if( EpilParserUtilities::IsUnaryOperator( this->GetTokens().GetCurrentToken() ) )
	{
		const EpilToken & opToken = this->GetTokens().GetCurrentToken();

		EpilUnaryExpressionCode * expr = new EpilUnaryExpressionCode( this->GetTokens().GetCurrentToken().location );
		expr->SetOperator( EpilParserUtilities::TranslateUnaryOperator( opToken ) );

		this->GetTokens().MoveToNext();

		EpilExpressionParser exprParser( this->GetTokens() );
		exprParser.ParseWithOperatorPrecedence( EpilParserUtilities::GetUnaryOperatorPrecedence( opToken ) );

		expr->SetExpression( exprParser.GetExpression() );

		leftExpr = expr;
	}
	else
	{
		EpilSimpleExpressionParser simpleExprParser( this->GetTokens() );
		simpleExprParser.Parse();
		leftExpr = simpleExprParser.GetExpression();
	}

	while( EpilParserUtilities::IsBinaryOperator( this->GetTokens().GetCurrentToken() ) &&
		   EpilParserUtilities::GetBinaryOperatorPrecedence( this->GetTokens().GetCurrentToken() ) > precedence )
	{
		const EpilToken & opToken = this->GetTokens().GetCurrentToken();

		EpilBinaryExpressionCode * expr = new EpilBinaryExpressionCode( leftExpr->GetLocation() );
		expr->SetLeftExpression( leftExpr );
		expr->SetOperator( EpilParserUtilities::TranslateBinaryOperator( opToken ) );

		this->GetTokens().MoveToNext();

		EpilExpressionParser rightExprParser( this->GetTokens() );
		try
		{
			rightExprParser.ParseWithOperatorPrecedence( EpilParserUtilities::GetBinaryOperatorPrecedence( opToken ) );
		}
		catch( ... )
		{
			EpilPointerHelper::SafeDelete( expr );
			throw;
		}
		expr->SetRightExpression( rightExprParser.GetExpression() );

		leftExpr = expr;
	}

	m_expression = leftExpr;
}